#include "./fiipCloudVar.h"
#define CLOUDVAR_LISTENERS_LEN_MAX 128
typedef struct {
  uint8_t* id;
  uint8_t* kVal;
  uint8_t kLen;
  void (*fun)(uint8_t* id, CloudVarStruct* var);
} CloudVar_ListenerStruct;  //监听器结构体
static CloudVar_ListenerStruct* ActualListeners[CLOUDVAR_LISTENERS_LEN_MAX];
static CloudVar_ListenerStruct* TargetListeners[CLOUDVAR_LISTENERS_LEN_MAX];
static uint16_t ActualListenersLen = 0;
static uint16_t TargetListenersLen = 0;
VarArrayStruct* fiipCloudVarLists = NULL;

void fiipCloudVar_init(void) {
  if (fiipCloudVarLists == NULL)
    fiipCloudVarLists = varArray_new();
}

static CloudVar_ListenerStruct* getListener(CloudVar_ListenerStruct** listeners,
                                            uint16_t listenersLen,
                                            uint8_t* id,
                                            uint8_t* kVal,
                                            uint8_t kLen) {
  for (int i = 0; i < listenersLen; i++) {
    if (listeners[i] != NULL) {
      if (mem_cmp(listeners[i]->id, id, 8) == 0) {
        if (listeners[i]->kLen == kLen) {
          if (mem_cmp(listeners[i]->kVal, kVal, kLen) == 0) {
            return listeners[i];
          }
        }
      }
    }
  }
  return NULL;
}
void fiipCloudVar_onActualChange(uint8_t* id,
                                 uint8_t* kVal,
                                 uint8_t kLen,
                                 void (*fun)(uint8_t* id,
                                             CloudVarStruct* var)) {
  CloudVar_ListenerStruct* listener =
      getListener(ActualListeners, ActualListenersLen, id, kVal, kLen);
  if (listener) {
    listener->fun = fun;
  } else {
    if (ActualListenersLen < CLOUDVAR_LISTENERS_LEN_MAX) {
      ActualListeners[ActualListenersLen] =
          (CloudVar_ListenerStruct*)mempool_alloc(
              sizeof(CloudVar_ListenerStruct));
      ActualListeners[ActualListenersLen]->id = id;
      ActualListeners[ActualListenersLen]->kLen = kLen;
      ActualListeners[ActualListenersLen]->kVal = kVal;
      ActualListeners[ActualListenersLen]->fun = fun;
      ActualListenersLen++;
    }
  }
}
void fiipCloudVar_onTargetChange(uint8_t* id,
                                 uint8_t* kVal,
                                 uint8_t kLen,
                                 void (*fun)(uint8_t* id,
                                             CloudVarStruct* var)) {
  CloudVar_ListenerStruct* listener =
      getListener(TargetListeners, TargetListenersLen, id, kVal, kLen);
  if (listener) {
    listener->fun = fun;
  } else {
    if (TargetListenersLen < CLOUDVAR_LISTENERS_LEN_MAX) {
      TargetListeners[TargetListenersLen] =
          (CloudVar_ListenerStruct*)mempool_alloc(
              sizeof(CloudVar_ListenerStruct));
      TargetListeners[TargetListenersLen]->id = id;
      TargetListeners[TargetListenersLen]->kLen = kLen;
      TargetListeners[TargetListenersLen]->kVal = kVal;
      TargetListeners[TargetListenersLen]->fun = fun;
      TargetListenersLen++;
    }
  }
}

LinkedListStruct* fiipCloudVar_getVarList(uint8_t* id) {
  LinkedListStruct* fiipCloudVarList = NULL;

  for (unsigned int i = 0; i < fiipCloudVarLists->length; i++) {
    fiipCloudVarList = (LinkedListStruct*)fiipCloudVarLists->data[i];
    if (mem_cmp(fiipCloudVarList->id, id, 8) == 0) {
      break;
    }
  }
  if (fiipCloudVarList == NULL) {
    fiipCloudVarList =
        (LinkedListStruct*)mempool_alloc(sizeof(LinkedListStruct));
    fiipCloudVarList->id = mempool_alloc(8);
    mem_cpy(fiipCloudVarList->id, id, 8);
    varArray_addData(fiipCloudVarLists, fiipCloudVarList);
  }
  return fiipCloudVarList;
}
CloudVarStruct* fiipCloudVar_get(uint8_t* id, uint8_t* kVal, uint8_t kLen) {
  LinkedListStruct* fiipCloudVarList = NULL;
  CloudVarStruct* var;

  fiipCloudVarList = fiipCloudVar_getVarList(id);
  fiipCloudVarList->current = fiipCloudVarList->first;
  while (fiipCloudVarList->current != NULL) {
    var = (CloudVarStruct*)fiipCloudVarList->current->data;
    if (mem_cmp(var->keyVal, kVal, kLen) == 0) {
      return var;
    }
    fiipCloudVarList->current = fiipCloudVarList->current->next;
  }
  return NULL;
}
void fiipCloudVar_setActual(uint8_t* id,
                            uint8_t* kVal,
                            uint8_t kLen,
                            uint8_t* vVal,
                            uint8_t vLen) {
  CloudVarStruct* var = fiipCloudVar_get(id, kVal, kLen);
  CloudVar_ListenerStruct* listener =
      getListener(ActualListeners, ActualListenersLen, id, kVal, kLen);
  uint8_t hadChange = 0;

  if (var) {
    if (var->actualLen != vLen) {
      hadChange = 1;
      var->actualLen = vLen;
      if (vLen != 0) {
        mempool_free(var->actualVal);
        var->actualVal = (uint8_t*)mempool_alloc(vLen);
        mem_cpy(var->actualVal, vVal, vLen);
      }
    } else {
      if (mem_cmp(var->actualVal, vVal, vLen) != 0) {
        hadChange = 1;
        mem_cpy(var->actualVal, vVal, vLen);
      }
    }
  } else {
    hadChange = 1;
    var = (CloudVarStruct*)mempool_alloc(sizeof(CloudVarStruct));
    var->keyLen = kLen;
    var->keyVal = (uint8_t*)mempool_alloc(kLen);
    mem_cpy(var->keyVal, kVal, kLen);
    var->actualLen = vLen;
    var->actualVal = NULL;
    if (vLen != 0) {
      var->actualVal = (uint8_t*)mempool_alloc(vLen);
      mem_cpy(var->actualVal, vVal, vLen);
    }
    linkedList_addData(fiipCloudVar_getVarList(id), var);
  }

  if (listener) {
    if (hadChange == 1) {
      listener->fun(id, var);
    }
  }
}
void fiipCloudVar_setTarget(uint8_t* id,
                            uint8_t* kVal,
                            uint8_t kLen,
                            uint8_t* vVal,
                            uint8_t vLen) {
  CloudVarStruct* var = fiipCloudVar_get(id, kVal, kLen);
  CloudVar_ListenerStruct* listener =
      getListener(TargetListeners, TargetListenersLen, id, kVal, kLen);
  uint8_t hadChange = 0;

  if (var) {
    if (var->targetLen != vLen) {
      hadChange = 1;
      var->targetLen = vLen;
      if (vLen != 0) {
        mempool_free(var->targetVal);
        var->targetVal = (uint8_t*)mempool_alloc(vLen);
        mem_cpy(var->targetVal, vVal, vLen);
      }
    } else {
      if (mem_cmp(var->targetVal, vVal, vLen) != 0) {
        hadChange = 1;
        mem_cpy(var->targetVal, vVal, vLen);
      }
    }
  } else {
    hadChange = 1;
    var = (CloudVarStruct*)mempool_alloc(sizeof(CloudVarStruct));
    var->keyLen = kLen;
    var->keyVal = (uint8_t*)mempool_alloc(kLen);
    mem_cpy(var->keyVal, kVal, kLen);
    var->targetLen = vLen;
    var->actualVal = NULL;
    if (vLen != 0) {
      var->targetVal = (uint8_t*)mempool_alloc(vLen);
      mem_cpy(var->targetVal, vVal, vLen);
    }
    linkedList_addData(fiipCloudVar_getVarList(id), var);
  }

  if (listener) {
    if (hadChange == 1) {
      listener->fun(id, var);
    }
  }
}
uint8_t fiipCloudVar_getActual(uint8_t* id,
                               uint8_t* kVal,
                               uint8_t kLen,
                               uint8_t* vVal) {
  CloudVarStruct* var;
  var = fiipCloudVar_get(id, kVal, kLen);
  if (var) {
    mem_cpy(vVal, var->actualVal, var->actualLen);
    return var->actualLen;
  } else {
    return 0;
  }
}
uint8_t fiipCloudVar_getTarget(uint8_t* id,
                               uint8_t* kVal,
                               uint8_t kLen,
                               uint8_t* vVal) {
  CloudVarStruct* var;
  var = fiipCloudVar_get(id, kVal, kLen);
  if (var) {
    mem_cpy(vVal, var->targetVal, var->targetLen);
    return var->targetLen;
  } else {
    return 0;
  }
}
